package me.ingxin.android.sysbar

import android.os.Build
import android.view.View
import android.view.Window
import android.view.WindowManager
import androidx.annotation.IntDef
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat

@Retention(AnnotationRetention.SOURCE)
@IntDef(
    value = [WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH, WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE, WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE]
)
private annotation class Behavior

/**
 * 设置屏幕是否常亮.
 * @param keep true常亮,false不常亮
 */
fun Window.keepScreenOn(keep: Boolean) {
    if (keep) {
        addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    } else {
        clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    }
}

/**
 * 设置状态栏亮色/暗色模式
 * @param light true设置为亮色模式，此时字体和图标为黑色，false为暗色模式，字体图标白色
 */
fun Window.setStatusBarsLightMode(light: Boolean) {
    val controller = WindowCompat.getInsetsController(this, decorView)
    controller.isAppearanceLightStatusBars = light
}

/**
 * 设置导航栏亮色/暗色模式
 * @param light true设置为亮色模式，此时字体和图标为黑色，反之为false
 */
fun Window.setNavigationBarsLightMode(light: Boolean) {
    val controller = WindowCompat.getInsetsController(this, decorView)
    controller.isAppearanceLightNavigationBars = light
}

/**
 * 开启Activity沉浸式,沉浸式会影响android:windowSoftInputMode="adjustResize"
 */
fun Window.immersion() {
    WindowCompat.setDecorFitsSystemWindows(this, false)
}

/**
 * 退出Activity沉浸式
 */
fun Window.exitImmersion() {
    WindowCompat.setDecorFitsSystemWindows(this, true)
}

/**
 * 全屏模式下状态栏适配
 * 该方法需要在onResume之前调用，之后调用不生效.
 */
fun Window.allowShortEdges() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        //隐藏状态栏时，需要申请允许绘制到状态栏下
        attributes.layoutInDisplayCutoutMode =
            WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
    }
}

/**
 * 进入全屏（收起状态栏和导航栏）,如果该方法在onResume之后调用，需要在onResume之前预先调用[allowShortEdges],否则状态栏会黑边
 *
 * 1.在全屏模式下，生命周期重新回到onResume会导致状态栏和导航栏出现，可在onResume中再次调用进入全屏
 * 2.开启全屏会开启沉浸式，如果开启全屏之前页面已经做了沉浸式适配,则布局不会在发生任何变化,此时可能出现状态栏和导航栏留白的情况，
 *   重新沉浸式并将状态栏和导航栏适配即可
 * 3.如果进入全屏前为非沉浸式则不会出现任何问题。
 *
 * @param behavior 导航栏和状态栏的显示模式
 */
@JvmOverloads
fun Window.fullScreen(@Behavior behavior: Int = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) {
    allowShortEdges()
    val controller = WindowCompat.getInsetsController(this, decorView)
    controller.hide(WindowInsetsCompat.Type.systemBars())
    controller.systemBarsBehavior = behavior
    //开启沉浸式
    immersion()
}

/**
 * 退出全屏（显示状态栏和导航栏）,会退出沉浸.如果需要页面需要沉浸式可以重新调用沉浸式[immersion]
 */
fun Window.exitFullScreen() {
    val controller = WindowCompat.getInsetsController(this, decorView)
    controller.show(WindowInsetsCompat.Type.systemBars())
    //退出沉浸式
    exitImmersion()
}

/**
 * 获取状态栏和导航栏高度,该方法在视图未Attach时会失败返回0
 * @return 返回（statusBarsHeight,navigationBarsHeight）
 */
fun View.getSystemBarsHeight(): Pair<Int, Int> {
    val windowInsets = ViewCompat.getRootWindowInsets(this)
    //insets返回各种bar的偏移量
    val insets = windowInsets?.getInsetsIgnoringVisibility(WindowInsetsCompat.Type.systemBars())
    val statusBarsHeight = insets?.top ?: 0
    val navigationBarsHeight = insets?.bottom ?: 0
    return statusBarsHeight to navigationBarsHeight
}

/**
 * 弹出输入法
 * @param focusView 触发的焦点view
 */
fun Window.showIME(focusView: View) {
    if (!focusView.isFocused) {
        focusView.isFocusableInTouchMode = true
        focusView.isFocusable = true
        focusView.requestFocus()
    }
    //兼容某些机型
    focusView.post {
        val controller = WindowCompat.getInsetsController(this, focusView)
        controller.show(WindowInsetsCompat.Type.ime())
    }
}

/**
 * 收起输入法
 * @param focusView 当前正在获得焦点的view(一般为EditTextView）
 */
fun Window.hideIME(focusView: View) {
    val controller = WindowCompat.getInsetsController(this, focusView)
    controller.hide(WindowInsetsCompat.Type.ime())
    //清除焦点,否则回到页面时会弹出输入法
    focusView.clearFocus()
}

/**
 * 收起输入法
 */
fun Window.hideIME() {
    decorView.findFocus()?.let { hideIME(it) }
}

/**
 * 输入法是否显示
 */
fun View.isVisibleIME(): Boolean {
    val insets = ViewCompat.getRootWindowInsets(this)
    return insets?.isVisible(WindowInsetsCompat.Type.ime()) == true
}

/**
 * 获取输入法高度
 */
fun View.getIMEHeight(): Int {
    val insets = ViewCompat.getRootWindowInsets(this)
    return insets?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
}